{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Example: combining MOD file ion channels with rxd" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A version of this notebook may be run online via Google Colab at https://tinyurl.com/neuron-rxd-and-mod\n", " (make a copy or open in playground mode)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overview" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "NEURON's reaction-diffusion infrastructure can be used to readily allow intracellular concentrations to respond to currents generated in MOD files, as long as:\n", "\n", "- `nrn_region='i'` is specified for the `rxd.Region` (so that it knows it corresponds to the electrophysiology region of the inside of the cell), AND\n", "the name and charge of the ion/etc are given in the `rxd.Species` declaration.\n", "Satisfying the above two rules also allows MOD files to see intracellular concentrations.\n", "\n", "- 3D extracellular concentrations also interoperate with electrophysiology automatically as long as name and charge are specified.\n", "\n", "As a simple example, we consider a model with just a single point soma, of length and diameter 10 microns, with Hodgkin-Huxley kinetics (which uses the built in mod file `hh.mod`), and dynamic sodium (declared using rxd but without any additional kinetics)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup NEURON library and imports" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's import our usual NEURON libraries and definitions. Remember you can use either `um` or `µm` for micron." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "execution": { "iopub.execute_input": "2026-05-28T21:17:44.493635Z", "iopub.status.busy": "2026-05-28T21:17:44.493352Z", "iopub.status.idle": "2026-05-28T21:17:44.927631Z", "shell.execute_reply": "2026-05-28T21:17:44.926907Z" } }, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from neuron import n, rxd\n", "from neuron.units import mV, ms, um, mM\n", "\n", "## needed for standard run system\n", "n.load_file(\"stdrun.hoc\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now import `plotly`, a graphics library. (You could easily modify this code to use other graphics libraries like `matplotlib`, `plotnine`, or `bokeh`.)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2026-05-28T21:17:44.997875Z", "iopub.status.busy": "2026-05-28T21:17:44.997438Z", "iopub.status.idle": "2026-05-28T21:17:45.065761Z", "shell.execute_reply": "2026-05-28T21:17:45.065052Z" } }, "outputs": [], "source": [ "import plotly.graph_objects as go\n", "from plotly.subplots import make_subplots" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup the model" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2026-05-28T21:17:45.069245Z", "iopub.status.busy": "2026-05-28T21:17:45.068996Z", "iopub.status.idle": "2026-05-28T21:17:45.117506Z", "shell.execute_reply": "2026-05-28T21:17:45.116800Z" } }, "outputs": [], "source": [ "## define morphology\n", "soma = n.Section(name=\"soma\")\n", "soma.L = soma.diam = 10 * um\n", "\n", "## add ion channels (n.hh is built in, so always available)\n", "n.hh.insert(soma)\n", "\n", "## define cytosol. MUST specify nrn_region for concentrations to update\n", "cyt = rxd.Region([soma], name=\"cyt\", nrn_region=\"i\")\n", "\n", "## define sodium. MUST specify name and charge for concentrations to update\n", "na = rxd.Species(cyt, name=\"na\", charge=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, we could have written `n.hh.insert(soma.wholetree())` to put Hodgkin-Huxley channels everywhere in the cell that the soma is part of, but since there is only one section, this is not required." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's also add an excitatory synapse to receive events (these will trigger the cell to spike)." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2026-05-28T21:17:45.120684Z", "iopub.status.busy": "2026-05-28T21:17:45.120420Z", "iopub.status.idle": "2026-05-28T21:17:45.125797Z", "shell.execute_reply": "2026-05-28T21:17:45.125193Z" } }, "outputs": [], "source": [ "syn = n.ExpSyn(soma(0.5))\n", "syn.tau = 1 * ms\n", "syn.e = 0 * mV" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Add a stimulus" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The spike events themselves (two events, 15 ms apart starting at n.t=10*ms):" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2026-05-28T21:17:45.128503Z", "iopub.status.busy": "2026-05-28T21:17:45.128291Z", "iopub.status.idle": "2026-05-28T21:17:45.132656Z", "shell.execute_reply": "2026-05-28T21:17:45.131977Z" } }, "outputs": [], "source": [ "stim = n.NetStim()\n", "stim.interval = 15 * ms\n", "stim.number = 2\n", "stim.start = 10 * ms" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Send those events to our synapse:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2026-05-28T21:17:45.135700Z", "iopub.status.busy": "2026-05-28T21:17:45.135408Z", "iopub.status.idle": "2026-05-28T21:17:45.140427Z", "shell.execute_reply": "2026-05-28T21:17:45.139654Z" } }, "outputs": [], "source": [ "nc = n.NetCon(stim, syn)\n", "nc.weight[0] = 0.001" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup recording variables" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2026-05-28T21:17:45.143355Z", "iopub.status.busy": "2026-05-28T21:17:45.143106Z", "iopub.status.idle": "2026-05-28T21:17:45.148796Z", "shell.execute_reply": "2026-05-28T21:17:45.148033Z" } }, "outputs": [], "source": [ "t = n.Vector().record(n._ref_t)\n", "v = n.Vector().record(soma(0.5)._ref_v)\n", "na_vec = n.Vector().record(soma(0.5)._ref_nai)\n", "ina = n.Vector().record(soma(0.5)._ref_ina)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Initialize and run the simulation" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2026-05-28T21:17:45.151897Z", "iopub.status.busy": "2026-05-28T21:17:45.151572Z", "iopub.status.idle": "2026-05-28T21:17:45.177228Z", "shell.execute_reply": "2026-05-28T21:17:45.176514Z" } }, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n.finitialize(-65 * mV)\n", "n.continuerun(50 * ms)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot it" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2026-05-28T21:17:45.180284Z", "iopub.status.busy": "2026-05-28T21:17:45.180043Z", "iopub.status.idle": "2026-05-28T21:17:45.581929Z", "shell.execute_reply": "2026-05-28T21:17:45.579302Z" } }, "outputs": [ { "data": { "text/html": [ " \n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "